package presistencia.dao;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import presistencia.conexao.Conexao;
import presistencia.interfaces.ContaDAO;
import presistencia.interfaces.MovimentacaoDAO;
import beans.GraficoDados;
import beans.Movimentacao;

public class MovimentacaoDAOImpl implements MovimentacaoDAO {

	
	private Conexao conexao;
	private ContaDAO creditoDAO;
	
	
	public MovimentacaoDAOImpl(Conexao conexao) {
		this.conexao = conexao;
	}
	
	@Override
	public long inserir(Movimentacao objeto) throws SQLException {
		PreparedStatement preparedStatement = 
			conexao.getPreparedStatement(
					"INSERT INTO movimentacoes (ds_movimentacao,dt_movimentacao,cd_credito,cd_debito,valor) VALUES (?,?,?,?,?)");
		
		preparedStatement.setString(1, objeto.getComentario());
		preparedStatement.setDate(2, new java.sql.Date( objeto.getData().getTime() ));
		preparedStatement.setLong(3, objeto.getCredito().getCodigo());
		preparedStatement.setLong(4, objeto.getDebito().getCodigo());
		preparedStatement.setBigDecimal(5, objeto.getValor());
		
		preparedStatement.executeUpdate();
		long extractId = Util.extractId(preparedStatement.getGeneratedKeys());
		preparedStatement.close();
		
		return 	extractId;

	}

	@Override
	public void deletar(Movimentacao objeto) throws SQLException {
		PreparedStatement preparedStatement = conexao.getPreparedStatement("DELETE from movimentacoes WHERE cd_movimentacao = ?");
		preparedStatement.setLong(1, objeto.getCodigo());
		preparedStatement.executeUpdate();
		preparedStatement.close();
	}

	@Override
	public void atualizar(Movimentacao objeto) throws SQLException {
		PreparedStatement preparedStatement = 
			conexao.getPreparedStatement(
					"UPDATE movimentacoes SET ds_movimentacao=?,dt_movimentacao=?,cd_credito=?,cd_debito=?,valor=? WHERE cd_movimentacao=?");
		
		preparedStatement.setString(1, objeto.getComentario());
		preparedStatement.setDate(2, new java.sql.Date(objeto.getData().getTime()));
		preparedStatement.setLong(3, objeto.getCredito().getCodigo());
		preparedStatement.setLong(4, objeto.getDebito().getCodigo());
		preparedStatement.setBigDecimal(5, objeto.getValor());
		preparedStatement.setLong(6, objeto.getCodigo());
		
		
		preparedStatement.executeUpdate();
		preparedStatement.close();

	}

	@Override
	public Movimentacao buscarID(long id) throws SQLException {
		Movimentacao movimentacao = null;
		
		PreparedStatement preparedStatement = conexao.getPreparedStatement("SELECT cd_movimentacao, ds_movimentacao, dt_movimentacao,cd_credito,cd_debito,valor FROM movimentacoes WHERE cd_movimentacao=?");
		preparedStatement.setLong(1, id);
		ResultSet query = preparedStatement.executeQuery();
		
		if(query.next()){
			movimentacao = bindMovimentacao(query);
		}
		
		return movimentacao;
		

	}
	
	@Override
	public List<Movimentacao> buscarTodos() throws SQLException {
		
		PreparedStatement preparedStatement = conexao.getPreparedStatement("SELECT cd_movimentacao, ds_movimentacao, dt_movimentacao,cd_credito,cd_debito,valor FROM movimentacoes");
		ResultSet query = preparedStatement.executeQuery();
		
		return bindMovimentacoes(query);
	}
	
	@Override
	public List<Movimentacao> buscarIntervaloData(Date inicial, Date final_) throws SQLException{
		PreparedStatement preparedStatement = conexao.getPreparedStatement
		("SELECT cd_movimentacao, ds_movimentacao, dt_movimentacao,cd_credito,cd_debito,valor FROM movimentacoes" +
				" where dt_movimentacao >= ? and dt_movimentacao <= ? ");
		
		preparedStatement.setDate(1, new java.sql.Date(inicial.getTime()));
		preparedStatement.setDate(2, new java.sql.Date(final_.getTime()));
		
		
		ResultSet query = preparedStatement.executeQuery();
				
		return bindMovimentacoes(query);
	}
	
	
	@Override
	public List<GraficoDados> getGraficoDados(java.util.Date dataInicial, java.util.Date dataFinal) throws SQLException{
		
		StringBuilder sb = new StringBuilder();
		sb.append("select c.cd_conta , c.NM_CONTA , if(cred.credito is null, 0 ,cred.credito) as credito,if(deb.debito is null,0,deb.debito) as debito, if(deb.debito-cred.credito is null, 0, deb.debito-cred.credito) as diferenca from contas c");
		sb.append(" left outer join (select sum(valor) as credito, CD_CREDITO from movimentacoes where DT_MOVIMENTACAO between ? and ? group by CD_CREDITO  ) as cred on cred.CD_CREDITO=c.CD_CONTA ");
		sb.append(" left outer join (select sum(valor) as debito, CD_DEBITO from movimentacoes where DT_MOVIMENTACAO between ? and ? group by CD_DEBITO ) as deb on deb.CD_DEBITO=c.CD_CONTA");
		System.out.println(sb.toString());
		
		PreparedStatement preparedStatement = conexao.getPreparedStatement(sb.toString());
		
		
		preparedStatement.setDate(1, new java.sql.Date(dataInicial.getTime()));
		preparedStatement.setDate(2, new java.sql.Date(dataFinal.getTime()));
		preparedStatement.setDate(3, new java.sql.Date(dataInicial.getTime()));
		preparedStatement.setDate(4, new java.sql.Date(dataFinal.getTime()));
		
		
		
		ResultSet query = preparedStatement.executeQuery();
		
		return bindGraficoDadosList(query);
		
	}
	
	private  GraficoDados bindGraficoDados(ResultSet query) throws SQLException{
		return new GraficoDados(creditoDAO.buscarID(query.getLong("cd_conta")), query.getBigDecimal("debito"), query.getBigDecimal("credito"), query.getBigDecimal("diferenca"));
	}
	
	private Movimentacao bindMovimentacao(ResultSet query) throws SQLException{
		Movimentacao.Builder builder = new Movimentacao.Builder();
		builder.codigo(query.getLong("cd_movimentacao"));
		builder.data(query.getDate("dt_movimentacao"));
		builder.comentario(query.getString("ds_movimentacao"));
		builder.credito(creditoDAO.buscarID(query.getLong("cd_credito")));
		builder.debito(creditoDAO.buscarID(query.getLong("cd_debito")));
		builder.valor(query.getBigDecimal("valor"));
		
		return builder.build();
	}
	
	private List<GraficoDados> bindGraficoDadosList(ResultSet query) throws SQLException{
		List<GraficoDados> gd = new ArrayList<GraficoDados>();
		
		while(query.next()){
			gd.add(bindGraficoDados(query));
		}
		
		return gd;
	}
	
	private List<Movimentacao> bindMovimentacoes(ResultSet query) throws SQLException{
		List<Movimentacao> movimentacoes = new ArrayList<Movimentacao>();
		
		while(query.next()){
			movimentacoes.add(bindMovimentacao(query));
		}
		
		return movimentacoes;
	}

	public void setCreditoDAO(ContaDAO creditoDAO) {
		this.creditoDAO = creditoDAO;
	}



	

}
